package cc.autoapi.pucong.auto.flow.core.flow.execNode.task.system;


import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.api.PropertiesVo;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.node.*;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.entity.task.ApiExecResult;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.exception.AutoDesignException;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.exec.DataBus;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.selfenum.DataTypeEnum;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.selfenum.RunStatusEnum;
import cc.autoapi.pucong.auto.flow.core.flow.execNode.utils.DataValueUtils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@Slf4j
public class ForTask extends ProcessTask {

    private List<NodeParamIn> paramsIns;
    private List<NodeParamOut> paramsOuts;
    private Object forDataList;
    private String paramsNameBreak;

    List<Object> forExecResultList = new ArrayList<>();

    public ForTask() {
        paramsIns = new ArrayList<>();

        paramsOuts = new ArrayList<>();
        NodeParamOut result = new NodeParamOut()
                .setParamCode("result")
                .setDateType(DataTypeEnum.LIST)
                .setDesc("循环结果");
        paramsOuts.add(result);
    }

    @Override
    public void run() {
        ExecNodeFor execNode = (ExecNodeFor) getExecNode();
        String forValue = execNode.getForValue();
        Integer forDataType = execNode.getForDataType();
        Object dateValue = null;
        // 参数类型 0静态值 1前置接口返回值 2全局参数
        if (forDataType == 1) {
            String paramValueId = JSONArray.parseArray(forValue).getString(1);
            if (StringUtils.isBlank(paramValueId)) {
                throw new AutoDesignException("for循环参数值错误");
            }
            // 获取值
            List<TaskNodeParamOut> taskNodeParamsOutList = DataBus.getTaskNodeParamsOutList(getApiId());
            TaskNodeParamOut taskNodeParamOut = taskNodeParamsOutList.stream().filter(s -> s.getUuid().equals(paramValueId)).findFirst().orElse(null);
            if (taskNodeParamOut != null) {
                ExecNode execNodeById = getExecNodeById(taskNodeParamOut.getApiNodeId());
                dateValue = execNodeById.getParamOutValue(taskNodeParamOut.getParamCode());
            } else {
                List<TaskNodeParamIn> taskNodeParamsInList = DataBus.getTaskNodeParamsInList(getApiId());
                TaskNodeParamIn taskNodeParamIn = taskNodeParamsInList.stream().filter(s -> s.getUuid().equals(paramValueId)).findFirst().orElse(null);
                if (taskNodeParamIn != null) {
                    ExecNode execNodeById = getExecNodeById(taskNodeParamIn.getApiNodeId());
                    dateValue = execNodeById.getParamInValue(taskNodeParamIn.getParamCode());
                }
            }
        } else if (forDataType == 0) {
            dateValue = forValue;
        } else if (forDataType == 2) {
            // 全局参数
            String propertyCode = com.alibaba.fastjson2.JSONArray.parseArray(forValue).getString(1);
            PropertiesVo property = DataBus.getProperty(propertyCode);
            if (property == null) {
                throw new AutoDesignException("for循环参数值错误");
            }
            dateValue = property.getPropertiesValue();
        }

        if (dateValue instanceof Integer ||
                dateValue instanceof JSONArray ||
                dateValue instanceof JSONObject ||
                dateValue instanceof List ||
                dateValue instanceof Map ||
                dateValue instanceof String) {
            forDataList = dateValue;
        } else {
            throw new AutoDesignException("不支持的循环类型");
        }
        // 获取中断参数
        List<ExecParamOut> paramOutList = execNode.getParamOutList();
        for (ExecParamOut execParamOut : paramOutList) {
            Boolean breakParams = execParamOut.getIsBreakParams();
            if (breakParams != null && breakParams) {
                paramsNameBreak = execParamOut.getParamCode();
            }
        }
        forDeal();
    }

    public void forDeal() {
        ExecNodeFor execNode = (ExecNodeFor) getExecNode();
        Boolean forAsync = execNode.getForAsync();

        // str转换
        if (forDataList instanceof String) {
            String str = (String) forDataList;
            try {
                Object json = JSONArray.parse(str);
                forDataList = json;
            } catch (Exception e) {
                try {
                    int parseInt = Integer.parseInt(str);
                    forDataList = parseInt;
                } catch (Exception e2) {
                }
            }
        }
        List<Future<ApiExecResult>> futureList = new ArrayList<>();
        // 发布执行事件
        if (forDataList instanceof JSONArray || forDataList instanceof List) {
            JSONArray array = JSONArray.parseArray(JSON.toJSONString(forDataList));
            for (int i = 0; i < array.size(); i++) {
                Object o = array.get(i);
                Future<ApiExecResult> submit = runItem(i, o);
                if (forAsync) {
                    // 异步执行
                    futureList.add(submit);
                } else {
                    // 同步执行
                    Boolean b = syncDealResult(submit);
                    if (b) {
                        break;
                    }
                }
            }
        } else if (forDataList instanceof JSONObject || forDataList instanceof Map) {
            JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(forDataList));
            Set<String> strings = jsonObject.keySet();
            for (String key : strings) {
                Future<ApiExecResult> submit = runItem(key, jsonObject.getJSONObject(key));
                if (forAsync) {
                    // 异步执行
                    futureList.add(submit);
                } else {
                    // 同步执行
                    Boolean b = syncDealResult(submit);
                    if (b) {
                        break;
                    }
                }
            }
        } else if (forDataList instanceof String) {
            String str = (String) forDataList;
            // 循环字符串
            for (int i = 0; i < str.length(); i++) {
                char c = str.charAt(i);
                Future<ApiExecResult> submit = runItem(i, c);
                if (forAsync) {
                    // 异步执行
                    futureList.add(submit);
                } else {
                    // 同步执行
                    Boolean b = syncDealResult(submit);
                    if (b) {
                        break;
                    }
                }
            }
        } else if (forDataList instanceof Integer) {
            Integer count = (Integer) forDataList;
            for (Integer i = 0; i < count; i++) {
                Future<ApiExecResult> submit = runItem(i, i);
                if (forAsync) {
                    // 异步执行
                    futureList.add(submit);
                } else {
                    // 同步执行
                    Boolean b = syncDealResult(submit);
                    if (b) {
                        break;
                    }
                }
            }
        } else {
            throw new AutoDesignException("不支持的循环类型");
        }
        // 需要等待所有子节点执行完成
        if (forAsync) {
            Boolean b = false;
            for (Future<ApiExecResult> future : futureList) {
                b = syncDealResult(future);
                if (b) {
                    // 尝试中断任务
                    future.cancel(true);
                }
            }
        }
        // 设置返回值
        setParamOutValue("result", forExecResultList);
    }

    private Boolean syncDealResult(Future<ApiExecResult> submit) {
        ApiExecResult result = null;
        try {
            result = submit.get(30, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("执行子流程异常: ", e);
            throw new AutoDesignException("执行子流程异常:" + e.getMessage());
        }
        RunStatusEnum runStatus = result.getRunStatus();
        if (runStatus == RunStatusEnum.执行成功) {
            Object data = result.getData();
            if (data instanceof JSONObject) {
                JSONObject parse = (JSONObject) data;
                forExecResultList.add(parse);
                if (paramsNameBreak != null) {
                    Object o = parse.get(paramsNameBreak);
                    if (o != null) {
                        if (o instanceof Boolean && (Boolean) o) {
                            return true;
                        } else if (o instanceof Integer && (Integer) o > 0) {
                            return true;
                        } else if (o instanceof String) {
                            String string = o.toString();
                            if (string.equals("true")) {
                                return true;
                            } else {
                                try {
                                    int parseInt = Integer.parseInt(string);
                                    if (parseInt > 0) {
                                        return true;
                                    }
                                } catch (Exception e) {
                                }
                            }
                        }
                    }
                }
            }
        } else if (runStatus == RunStatusEnum.执行失败) {
            throw new AutoDesignException(result.getErrorLog());
        }
        return false;
    }

    /**
     * 执行子节点
     *
     * @param itemKey
     * @param itemValue
     */
    private Future<ApiExecResult> runItem(Object itemKey, Object itemValue) {
        ExecNodeFor execNode = (ExecNodeFor) getExecNode();
        String processId = execNode.getProcessId();
        // 设置输入参数
        List<ExecParamIn> paramInList = getExecNode().getParamInList();
        for (ExecParamIn execParamIn : paramInList) {
            String paramValue = execParamIn.getParamValue();
            DataTypeEnum dateType = execParamIn.getDateType();
            String paramValueId = JSONArray.parseArray(paramValue).getString(1);
            if ("itemKey".equals(paramValueId)) {
                execParamIn.setDateValue(DataValueUtils.transDataType(execParamIn.getParamCode(), dateType, itemKey));
            }
            if ("itemValue".equals(paramValueId)) {
                execParamIn.setDateValue(DataValueUtils.transDataType(execParamIn.getParamCode(), dateType, itemValue));
            }
        }
        // 子流程执行
        Future<ApiExecResult> apiExecResultFuture = processExec(processId);
        return apiExecResultFuture;
    }

    @Override
    public String getTaskName() {
        return "循环节点";
    }

    @Override
    public String getTaskDesc() {
        return " 本组件为循环组件，可以根据设置的属性信息和子流程id，把参数遍历放入子流程中执行。\n" +
                "                \n" +
                "                本组件有4个属性可以设置，分别是:\n" +
                "                1.forDataType：参数类型 0静态值 1前置接口返回值 2全局参数\n" +
                "                2.forValue: 需要循环执行的值\n" +
                "                3.forAsync：是否异步执行\n" +
                "                4.processId： 子流程id\n" +
                "                \n" +
                "                本组件没有输入参数。\n" +
                "                \n" +
                "                本组件有1个输出参数，参数编码为result，是数组类型，每次循环执行的结果值就会放到该数组中。";
    }

    @Override
    public String getTaskSvgIcon() {
        return "<svg t=\"1727020869424\" class=\"icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"48474\" width=\"32\" height=\"32\"><path d=\"M512 0C228.693333 0 0 228.693333 0 512s228.693333 512 512 512 512-228.693333 512-512S795.306667 0 512 0z m317.44 747.52c0 27.306667-23.893333 51.2-51.2 51.2H245.76c-27.306667 0-51.2-23.893333-51.2-51.2v-208.213333H109.226667l98.986666-122.88L307.2 539.306667H228.693333v197.973333c0 13.653333 13.653333 27.306667 27.306667 27.306667h512c13.653333 0 27.306667-13.653333 27.306667-27.306667v-10.24h34.133333v20.48z m-467.626667-242.346667c0-27.306667 23.893333-51.2 51.2-51.2s51.2 23.893333 51.2 51.2-23.893333 51.2-51.2 51.2-51.2-23.893333-51.2-51.2z m170.666667 0c0-27.306667 23.893333-51.2 51.2-51.2s51.2 23.893333 51.2 51.2-23.893333 51.2-51.2 51.2-51.2-23.893333-51.2-51.2z m279.893333 109.226667l-98.986666-122.88h81.92v-204.8c0-13.653333-13.653333-27.306667-27.306667-27.306667h-512c-13.653333 0-27.306667 13.653333-27.306667 27.306667v23.893333h-34.133333v-34.133333c0-27.306667 23.893333-51.2 51.2-51.2h532.48c27.306667 0 51.2 23.893333 51.2 51.2v215.04h85.333333l-102.4 122.88z\" fill=\"#3A87FB\" p-id=\"48475\"></path></svg>";
    }

    @Override
    public List<NodeParamIn> getPropertyParamsIns() {
        return paramsIns;
    }

    @Override
    public List<NodeParamOut> getPropertyParamsOuts() {
        return paramsOuts;
    }
}
